import logging
from datetime import timedelta
from typing import Any

from fastapi import APIRouter, Depends, HTTPException, status, Body
from fastapi.responses import ORJSONResponse
from fastapi.security import OAuth2PasswordBearer
from jose import JWTError, jwt
from requests.exceptions import RequestException
from sqlalchemy.orm import Session

from app.core import security
from app.core.config import settings
from app.db.session import get_db
from app.models.user import User
from app.schemas.result import BaseResult, okResult, errResult
from app.schemas.token import LoginForm, TokenInfoResult, TokenUser
from app.schemas.user import UserCreate
from app.utils.str_utils import str_prominent

logger=logging.getLogger(__name__)

router = APIRouter()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@router.post("/register", response_model=BaseResult)
def register(*, db: Session = Depends(get_db), user_in: UserCreate) -> Any:
    """
    Register a new user.
    """
    try:
        # Check if user with this email exists
        user = db.query(User).filter(User.email == user_in.email).first()
        if user:
            raise HTTPException(
                status_code=400,
                detail="A user with this email already exists.",
            )

        # Check if user with this username exists
        user = db.query(User).filter(User.username == user_in.username).first()
        if user:
            raise HTTPException(
                status_code=400,
                detail="A user with this username already exists.",
            )

        # Create new user
        user = User(
            email=user_in.email,
            username=user_in.username,
            hashed_password=security.get_password_hash(user_in.password),
        )
        db.add(user)
        db.commit()
        db.refresh(user)
        return user
    except RequestException as e:
        raise HTTPException(
            status_code=503,
            detail="Network error or server is unreachable. Please try again later.",
        ) from e


@router.post("/token", response_model=BaseResult)
def login_access_token(db: Session = Depends(get_db), form_data: LoginForm= Body()) -> Any:
    """
    OAuth2 compatible token login, get an access token for future requests.
    """
    logger.debug(str_prominent("login_access_token"))
    user = db.query(User).filter(User.username == form_data.username).first()
    if not user or not security.verify_password(form_data.password, user.hashed_password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    elif not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Inactive user",
            headers={"WWW-Authenticate": "Bearer"},
        )

    access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = security.create_access_token(
        data={"sub": user.username}, expires_delta=access_token_expires
    )
    data={"token": access_token, "token_type": "bearer"}
    return okResult(data=data)


def get_current_user(
        db: Session = Depends(get_db),
        token: str = Depends(oauth2_scheme)
) -> User:
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception

    user = db.query(User).filter(User.username == username).first()
    if user is None:
        raise credentials_exception
    return user


@router.get("/getUserInfo", response_model=TokenInfoResult)
def get_user_info(current_user: User = Depends(get_current_user)) -> Any:
    """
    获取用户信息
    """
    user = TokenUser(
        username=current_user.username,
        email=current_user.email,
        nickname=current_user.nickname,
        id=current_user.id,
    )
    result = TokenInfoResult(user=user)
    return result




@router.get("/getUserProfile")
def get_user_profile(current_user:User=Depends(get_current_user)) -> Any:
    """
    获取用户信息
    """
    result = okResult(data=current_user)
    return result.json_encoders()


@router.put("/updatePwd")
def update_pwd(db: Session = Depends(get_db), user:User=Depends(get_current_user), old_pwd:str=Body(), new_pwd:str=Body()) -> Any:
    """
    获取用户信息
    """
    if not user or not security.verify_password(old_pwd, user.hashed_password):
        # raise errResult(msg="旧密码错误")
        raise HTTPException(
            status_code=500,
            detail="旧密码错误.",
        )

    user.hashed_password=security.get_password_hash(new_pwd)
    db.add(user)
    db.commit()
    db.refresh(user)
    return okResult()